package com.wframe.project.jnd.controller;

import com.frame.database.JdataBean;
import com.github.binarywang.wxpay.bean.WxPayOrderNotifyResponse;
import com.github.binarywang.wxpay.bean.request.WxPayBaseRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.wframe.project.former.enums.OrderStatusEnum;
import com.wframe.project.jnd.entity.Payment;
import com.wframe.project.jnd.rest.util.ClientException;
import com.wframe.project.jnd.rest.util.JsonReturn;
import com.wframe.project.jnd.rest.util.WebSession;
import com.wframe.project.jnd.services.OrderService;
import com.wframe.project.jnd.services.PayService;
import com.wframe.project.jnd.util.ServletUtils;
import com.wframe.project.jnd.wx.wxImpl.WeixAccountConfig;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by lwb on 2017/5/6.
 */
@Controller
@RequestMapping("/payment")
public class PayOnlineController {
    private Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    private PayService payService;

    @Autowired
    private WeixAccountConfig tempWechatConfig;

    @Autowired
    private OrderService orderService;

    private static WxPayConfig wechatPayConfig;

    private static WxPayService wxPayService;

    private void initWechatConfig() {
        if (this.wechatPayConfig == null) {
            this.wechatPayConfig = new WxPayConfig();
            this.wechatPayConfig.setAppId(this.tempWechatConfig.getAppId());
            this.wechatPayConfig.setMchId(this.tempWechatConfig.getMch_id());
            this.wechatPayConfig.setMchKey(this.tempWechatConfig.getPayKey());
            this.wechatPayConfig.setTradeType("NATIVE");
            this.wechatPayConfig.setNotifyUrl(this.tempWechatConfig.getNotifyUrl());

            this.wxPayService = new WxPayServiceImpl();
            this.wxPayService.setConfig(this.wechatPayConfig);
        }
    }

    /**
     * 显示收银台页面
     *
     * @param code
     * @param model
     * @return
     */
    @RequestMapping(value = "/cashier/{code}", method = RequestMethod.GET)
    public String showCashier(@PathVariable String code, Model model, HttpSession session) {
        String url = WebSession.checkWbUserStatus(session);
        if (!"success".equalsIgnoreCase(url)) {
            return url;
        }

        JdataBean order = orderService.getOrderByCode(code);
        Assert.notNull(order, "订单号为" + code + "的订单不存在");

        model.addAllAttributes(order.getDataMap());
        return "/website/order/cashier";
    }

    /**
     * 货到付款
     *
     * @param code
     * @param session
     * @return
     */
    @RequestMapping(value = "/delivery/{code}", method = RequestMethod.GET)
    public String updatePayType(@PathVariable String code, HttpSession session) {
        String url = WebSession.checkWbUserStatus(session);
        if (!"success".equalsIgnoreCase(url)) {
            return url;
        }

        JdataBean order = orderService.getOrderByCode(code);
        Assert.notNull(order, "订单号为" + code + "的订单不存在");
        //订单已提交
        if (order.getInt("status") == OrderStatusEnum.Confirm.getStatus()) {
            return "redirect:/order/showorderOk?ordercode=" + code;
        }

        Assert.isTrue(order.getInt("status") == OrderStatusEnum.NoPay.getStatus() && order.getInt("paytype") != 2 && order.getInt("ispay") == 0 && order.getBigDecimal("pay_money") != null && order.getBigDecimal("pay_money").compareTo(BigDecimal.ZERO) > 0,
                "订单必须为未支付状态,支付金额必须大于0");
        orderService.updateConfirmByCode(code);
        return "redirect:/order/showorderOk?ordercode=" + code;
    }

    /**
     * 微信支付页面
     *
     * @param code
     * @param request
     * @param model
     * @return
     * @throws ClientException
     */
    @RequestMapping(value = "/{code}", method = RequestMethod.GET)
    public String showQRCode(@PathVariable String code, HttpServletRequest request, ModelMap model) throws ClientException {
        String url = WebSession.checkWbUserStatus(request.getSession());
        if (!"success".equalsIgnoreCase(url)) {
            return url;
        }

        JdataBean order = orderService.findOrderTips(code);
        Assert.isTrue(order.getInt("status") == OrderStatusEnum.NoPay.getStatus() && order.getInt("paytype") != 2 && order.getInt("ispay") == 0 && order.getBigDecimal("pay_money") != null && order.getBigDecimal("pay_money").compareTo(BigDecimal.ZERO) > 0,
                "订单必须为未支付状态,支付金额必须大于0");

        model.put("order_type", Payment.PayOrderType.PRODUCT_ORDER.name());
        model.put("order_sn", code);
        model.put("pay_way", Payment.PayWay.WECHAT_QR.name());
        model.put("pay_state", Arrays.asList(new String[]{Payment.PayState.GENERATED.name(), Payment.PayState.SUBMITTED.name()}));
        Payment payment = payService.getOrder(model);
        if (payment == null) {
            //生成支付订单
            payment = new Payment();
            payment.setAmount(order.getBigDecimal("pay_money"));
            payment.setOrder_type(Payment.PayOrderType.PRODUCT_ORDER);
            payment.setOrder_sn(order.getString("code"));
            payment.setPay_way(Payment.PayWay.WECHAT_QR);
            payment = payService.generateOrder(payment);
            Assert.notNull(payment, "生成支付订单失败");
        }


        initWechatConfig();
        WxPayUnifiedOrderRequest orderRequest = WxPayUnifiedOrderRequest.builder().build();

        orderRequest.setBody("商品订单支付");
        String sn = payment.getSn();
        orderRequest.setOutTradeNo(sn);
        orderRequest.setTotalFee(WxPayBaseRequest.yuanToFee(payment.getAmount().toString()));
        orderRequest.setSpbillCreateIp(ServletUtils.getClientIP(request));
        orderRequest.setTimeStart(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
        orderRequest.setProductId(sn);

        try {
            //调用统一下单接口
            Map<String, String> payInfo = this.wxPayService.getPayInfo(orderRequest);
            model.addAllAttributes(order.getDataMap());
            model.addAttribute("codeUrl", payInfo.get("codeUrl"));
            model.addAttribute("payment", payment);
        } catch (Exception e) {
            log.error("微信支付失败！支付订单号：{},原因:{}", sn, e.getMessage());
            e.printStackTrace();
            return "redirect:/payment/result/fail/" + code;
        }
        //修改支付订单状态为已提交
        payService.updateSubmitted(sn);

        return "/website/order/wechatpayment";
    }

    /**
     * 查询订单是否支付成功
     *
     * @param sn
     * @return
     */
    @RequestMapping(value = "/state/{sn}", method = RequestMethod.GET)
    @ResponseBody
    public String findPayment(@PathVariable String sn) {
        JsonReturn json = new JsonReturn();
        Object state = payService.findAttribute("pay_state", "sn", sn);
        Assert.notNull(state, "支付订单号为" + sn + "的订单不存在");

        Payment.PayState payState = Payment.PayState.valueOf(String.valueOf(state));
        switch (payState) {
            case SUCCESS:
                json.putData("success");
                break;
            case FAILURE:
                json.putData("fail");
                break;
        }

        return json.toString();
    }

    /**
     * 跳转支付结果页面
     *
     * @param state
     * @param code
     * @param model
     * @return
     */
    @RequestMapping(value = "/result/{state}/{code}", method = RequestMethod.GET)
    public String showPayResult(@PathVariable String state,HttpSession session, @PathVariable String code, Model model) {
        String url = WebSession.checkWbUserStatus(session);
        if (!"success".equalsIgnoreCase(url)) {
            return url;
        }
        if ("success".equalsIgnoreCase(state)) {
            JdataBean order = orderService.getOrderByCode(code);
            Assert.notNull(order, "订单号为" + code + "的订单不存在");
            model.addAllAttributes(order.getDataMap());
            return "/website/order/wechatpaymentsuccess";
        } else {
            model.addAttribute("code", code);
            return "/website/order/failure";
        }
    }

    @RequestMapping("wxNotifyBack")
    public String wxNotifyBack(HttpServletRequest request) throws Exception {
        try {

            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

            initWechatConfig();
            String xml = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());

            System.out.println(xml);

            WxPayOrderNotifyResult result = this.wxPayService.getOrderNotifyResult(xml);
            String payCode = result.getOutTradeNo();     //sn

            System.out.println("支付单号：" + payCode);

            WxPayOrderQueryResult queryResult = wxPayService.queryOrder(null, payCode);
            String transactionId = queryResult.getTransactionId();    // 微信订单号

            int totalfee = queryResult.getTotalFee();
            payCode = queryResult.getOutTradeNo();
            Payment payMent = payService.getOrderByCode(payCode);
            if (payMent == null) {
                return WxPayOrderNotifyResponse.success("支付失败,支付订单不存在");
            }

            if (payMent.getPay_state() != Payment.PayState.GENERATED && payMent.getPay_state() != Payment.PayState.SUBMITTED) {
                return WxPayOrderNotifyResponse.success("支付订单已处理");
            }

            String tradeState = queryResult.getTradeState(); //返回的支付订单状态

            System.out.println("微信查询交易状态：" + tradeState);

            Map map = new HashMap();
            Map keyMap = new HashMap();
            keyMap.put("sn", payCode);
            JdataBean order = null;

            if ("USERPAYING".equalsIgnoreCase(tradeState)) {
                return WxPayOrderNotifyResponse.success("用户支付中");
            }

            if (!"SUCCESS".equalsIgnoreCase(tradeState)) {
                map.put("pay_time", new Date());
                map.put("fail_reason", queryResult.getReturnMsg());
                map.put("pay_state", Payment.PayState.FAILURE.toString());
                payService.update(map, keyMap);
                return WxPayOrderNotifyResponse.fail("微信订单支付失败");
            }

            System.out.println("支付订单类型：" + payMent.getOrder_type());

            //支付订单支付类型错误
            if (Payment.PayOrderType.PRODUCT_ORDER != payMent.getOrder_type()) {
                map.put("pay_time", new Date());
                map.put("pay_sn", transactionId);
                map.put("pay_state", Payment.PayState.FAILURE.toString());
                map.put("fail_reason", "支付类型错误,支付失败");
                payService.update(map, keyMap);
                return WxPayOrderNotifyResponse.success("支付类型错误,支付失败");
            }

            System.out.println("支付订单关联订单号：" + payMent.getOrder_sn());

            //商品订单为空
            if (StringUtils.isEmpty(payMent.getOrder_sn())) {
                map.put("pay_time", new Date());
                map.put("pay_sn", transactionId);
                map.put("fail_reason", "商品订单不存在,支付失败");
                payService.update(map, keyMap);
                return WxPayOrderNotifyResponse.success("商品订单不存在,支付失败");
            }

            System.out.println("支付订单支付状态：" + payMent.getPay_state());

            //支付订单不为SUCCESS
            if (Payment.PayState.SUCCESS != payMent.getPay_state()) {
                map.put("pay_state", Payment.PayState.SUCCESS.toString());
                map.put("pay_time", new Date());
                map.put("pay_sn", transactionId);
                payService.update(map, keyMap);
            }

            order = orderService.getOrderByCode(payMent.getOrder_sn());
            Integer orderStatus = order.getInt("status");
            BigDecimal orderAmount = order.getBigDecimal("pay_money");

            System.out.println("支付订单关联订单状态：" + orderStatus);
            System.out.println("支付订单关联订单金额：" + orderAmount);

            //商品订单已经成功,直接返回成功
            if (orderStatus >= 2) {
                return WxPayOrderNotifyResponse.success("支付成功");
            }

            BigDecimal amount = payService.getBigDecimalAmout(payCode);//支付订单总金额

            System.out.println("支付订单已支付总金额：" + amount);

            if (amount.compareTo(orderAmount) < 0) {
                return WxPayOrderNotifyResponse.success("支付成功");
            }

            if (amount.compareTo(orderAmount) > 0) {
                BigDecimal moreAmount = amount.subtract(orderAmount);
                map.put("remark", "用户多付的金额" + moreAmount);
                payService.update(map, keyMap);
            }

            if (payMent.getOrder_type() == Payment.PayOrderType.PRODUCT_ORDER) {
                orderService.updateStatusCode(payMent.getOrder_sn(), payMent.getPay_way().name(), transactionId);

                System.out.println("支付状态更新成功");

            }

            System.out.println("支付回调完成");

            return WxPayOrderNotifyResponse.success("支付成功");
        } catch (Exception e) {
            System.out.println("发生异常：" + e.getMessage());
            e.printStackTrace();
            return WxPayOrderNotifyResponse.fail("网络错误支付失败");
        } finally {
            System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        }
    }

}
